
package br.com.aeternu.controleatendimento.excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import br.com.aeternu.controleatendimento.common.bean.CommonBean;
import br.com.aeternu.controleatendimento.common.ifc.IfcMensagemUsuario;
import br.com.aeternu.controleatendimento.exception.ControleAtendimentoException;
import br.com.aeternu.controleatendimento.util.PropertyUtil;

public abstract class Excel
{

   protected static final String SHEET_AGENDAS = "Agendas";
   protected static final String SHEET_CONCLUSOES = "Conclusões";
   protected static final String SHEET_EMPRESAS = "Empresas";
   protected static final String SHEET_MEDICOS = "Médicos";
   protected static final String SHEET_TIPOEXAMES = "Tipos de Exames";
   protected static final String SHEET_TURNOS = "Turnos";
   private static Logger logger = Logger.getLogger(Excel.class);
   protected String arquivoExcel;
   protected DateFormat dateFormat;
   protected DateFormat sheetNameDateFormat;
   private HSSFCellStyle cellStyleCabecalho;
   private FileInputStream fileInputStream;
   private HSSFFont fontCabecalho;
   private HSSFFont fontGeral;

   public Excel()
   {
      arquivoExcel = PropertyUtil.getProperty(PropertyUtil.PRP_LOCAL_BASE);
      dateFormat = new SimpleDateFormat("dd/MM/yyyy");
      sheetNameDateFormat = new SimpleDateFormat("MMM-yyyy");

      logger.debug("Nome do arquivo: " + arquivoExcel);
   }

   public abstract void atualiza(CommonBean bean);

   public abstract void atualiza(List<? extends CommonBean> beanList);

   public abstract List<? extends CommonBean> obterRegistros() throws ControleAtendimentoException;

   protected void criarNovaPlanilha(boolean criandoNovoArquivo, Date data) throws ControleAtendimentoException
   {
      HSSFWorkbook workbook = null;

      if (criandoNovoArquivo)
      {
         workbook = criarNovaPastaDeTrabalho();
      }
      else
      {
         workbook = obterPastaDeTrabalho();
      }

      try
      {
         HSSFSheet sheet = workbook.createSheet(obterNomeDaPlanilha(data));

         // Linha do Cabeçalho
         HSSFRow row = sheet.createRow(0);
         // Data
         HSSFCell cell = row.createCell(0);
         cell.setCellValue("Data");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Turno
         cell = row.createCell(1);
         cell.setCellValue("Turno");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Médico
         cell = row.createCell(2);
         cell.setCellValue("Médico");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Paciente
         cell = row.createCell(3);
         cell.setCellValue("Paciente");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Tipo de Exame
         cell = row.createCell(4);
         cell.setCellValue("Tipo de Exame");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Coordenação
         cell = row.createCell(5);
         cell.setCellValue("Coordenação");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Empresa Parceira
         cell = row.createCell(6);
         cell.setCellValue("Empresa Parceira");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Particular
         cell = row.createCell(7);
         cell.setCellValue("Particular");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Conclusão/Pendência
         cell = row.createCell(8);
         cell.setCellValue("Conclusão/Pendência");
         cell.setCellStyle(getCellStyleCabecalho(workbook));
         // Quantidade
         cell = row.createCell(9);
         cell.setCellValue("Quantidade");
         cell.setCellStyle(getCellStyleCabecalho(workbook));

         FileOutputStream fileOut = new FileOutputStream(arquivoExcel);
         workbook.write(fileOut);
         fileOut.close();
      }
      catch (FileNotFoundException e)
      {
         logger.error(IfcMensagemUsuario.ERRO_ARQUIVO_ABERTO, e);
         throw new ControleAtendimentoException(IfcMensagemUsuario.ERRO_ARQUIVO_ABERTO);
      }
      catch (IOException e)
      {
         logger.error(IfcMensagemUsuario.ERRO_GRAVACAO_ARQUIVO, e);
         throw new ControleAtendimentoException(IfcMensagemUsuario.ERRO_GRAVACAO_ARQUIVO);
      }
   }

   protected boolean getBoolean(HSSFCell cell)
   {
      try
      {
         if (cell != null)
         {
            switch (cell.getCellType())
            {
               case HSSFCell.CELL_TYPE_STRING:
               {
                  return cell.getRichStringCellValue().getString().equalsIgnoreCase("SIM");
               }
            }
         }
      }
      catch (Exception e)
      {
         logger.error(e.getMessage(), e);
      }

      return false;
   }

   protected HSSFCellStyle getCellStyleGeral(HSSFWorkbook workbook)
   {
      getFontGeral(workbook);

      HSSFCellStyle cellStyleGeral = workbook.createCellStyle();
      cellStyleGeral.setFont(workbook.getFontAt((short) 6));
      cellStyleGeral.setAlignment(HSSFCellStyle.ALIGN_CENTER);
      cellStyleGeral.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
      cellStyleGeral.setFillForegroundColor(new HSSFColor.WHITE().getIndex());
      cellStyleGeral.setBorderBottom(HSSFCellStyle.BORDER_THIN);
      cellStyleGeral.setBottomBorderColor(HSSFColor.BLACK.index);
      cellStyleGeral.setBorderLeft(HSSFCellStyle.BORDER_THIN);
      cellStyleGeral.setLeftBorderColor(HSSFColor.BLACK.index);
      cellStyleGeral.setBorderRight(HSSFCellStyle.BORDER_THIN);
      cellStyleGeral.setRightBorderColor(HSSFColor.BLACK.index);
      cellStyleGeral.setBorderTop(HSSFCellStyle.BORDER_THIN);
      cellStyleGeral.setTopBorderColor(HSSFColor.BLACK.index);

      return cellStyleGeral;
   }

   /**
    * Obtém o conteúdo de uma célula no formato de data.
    * 
    * @param cell célula da planilha
    * @return null ou uma data.
    */
   protected Date getDate(HSSFCell cell)
   {
      try
      {
         if (cell != null)
         {
            switch (cell.getCellType())
            {
               case HSSFCell.CELL_TYPE_NUMERIC:
               {
                  return cell.getDateCellValue();
               }
               case HSSFCell.CELL_TYPE_STRING:
               {
                  return dateFormat.parse(cell.getRichStringCellValue().getString());
               }
            }
         }
      }
      catch (Exception e)
      {
         logger.error(e.getMessage(), e);
      }

      return null;
   }

   protected int getInteger(HSSFCell cell)
   {
      try
      {
         if (cell != null)
         {
            switch (cell.getCellType())
            {
               case HSSFCell.CELL_TYPE_STRING:
               {
                  return Integer.parseInt(cell.getRichStringCellValue().getString());
               }
               case HSSFCell.CELL_TYPE_NUMERIC:
               {
                  return (int) cell.getNumericCellValue();
               }
            }
         }
      }
      catch (Exception e)
      {
         logger.error(e.getMessage(), e);
      }

      return 0;
   }

   protected abstract HSSFSheet getSheet() throws ControleAtendimentoException;

   protected abstract HSSFSheet getSheet(HSSFWorkbook workbook) throws ControleAtendimentoException;

   /**
    * Obtém o texto contido em uma célula.
    * 
    * @param cell célula da planilha.
    * @return Texto ou vazio.
    */
   protected String getString(HSSFCell cell)
   {
      try
      {
         if (cell != null)
         {
            switch (cell.getCellType())
            {
               case HSSFCell.CELL_TYPE_STRING:
               {
                  return (cell.getRichStringCellValue().getString());
               }
               case HSSFCell.CELL_TYPE_NUMERIC:
               {
                  return String.valueOf(cell.getNumericCellValue());
               }
            }
         }
      }
      catch (Exception e)
      {
         logger.error(e.getMessage(), e);
      }

      return "";
   }

   protected void gravar(HSSFWorkbook workbook) throws IOException
   {
      FileOutputStream fileOut = new FileOutputStream(arquivoExcel);
      workbook.write(fileOut);
      fileOut.close();
   }

   /**
    * Obtém a pasta de trabalho.
    * <p>
    * Cria uma nova pasta de trabalho caso a pasta referenciada ainda não exista.
    * 
    * @return a pasta de trabalho
    * @throws ControleAtendimentoException
    * @exception RHourException
    */
   protected HSSFWorkbook obterPastaDeTrabalho() throws ControleAtendimentoException
   {
      HSSFWorkbook workbook = null;

      File file = new File(arquivoExcel);

      try
      {
         if (!file.exists())
         {
            criarNovaPlanilha(true);
         }

         POIFSFileSystem fs;
         fileInputStream = new FileInputStream(arquivoExcel);
         fs = new POIFSFileSystem(fileInputStream);
         workbook = new HSSFWorkbook(fs);
      }
      catch (FileNotFoundException e)
      {
         logger.error(IfcMensagemUsuario.ERRO_ARQUIVO_ABERTO, e);
         throw new ControleAtendimentoException(IfcMensagemUsuario.ERRO_ARQUIVO_ABERTO);
      }
      catch (IOException e)
      {
         logger.error(IfcMensagemUsuario.ERRO_GRAVACAO_ARQUIVO, e);
         throw new ControleAtendimentoException(IfcMensagemUsuario.ERRO_GRAVACAO_ARQUIVO);
      }

      return workbook;
   }

   private HSSFWorkbook criarNovaPastaDeTrabalho() throws ControleAtendimentoException
   {
      HSSFWorkbook workbook = new HSSFWorkbook();

      HSSFCellStyle cellStyleCabecalho = getCellStyleCabecalho(workbook);
      HSSFCellStyle cellStyleGeral = getCellStyleGeral(workbook);

      criarNovaPlanilhaAgendas(workbook, cellStyleCabecalho, cellStyleGeral);
      criarNovaPlanilhaConclusoes(workbook, cellStyleCabecalho, cellStyleGeral);
      criarNovaPlanilhaEmpresas(workbook, cellStyleCabecalho, cellStyleGeral);
      criarNovaPlanilhaMedicos(workbook, cellStyleCabecalho, cellStyleGeral);
      criarNovaPlanilhaTipoExames(workbook, cellStyleCabecalho, cellStyleGeral);
      criarNovaPlanilhaTurnos(workbook, cellStyleCabecalho, cellStyleGeral);

      return workbook;
   }

   /**
    * Cria uma nova planilha ou uma nova pasta de trabalho.
    * 
    * @param criandoNovoArquivo Indicador se será criada nova pasta de trabalho.
    * @throws ControleAtendimentoException
    */
   private void criarNovaPlanilha(boolean criandoNovoArquivo) throws ControleAtendimentoException
   {
      criarNovaPlanilha(criandoNovoArquivo, new Date());
   }

   protected void criarNovaPlanilhaAgendas(HSSFWorkbook workbook, HSSFCellStyle... cellStyles) throws ControleAtendimentoException
   {
      HSSFSheet sheet = workbook.createSheet(SHEET_AGENDAS);

      // Linha do Cabeçalho
      HSSFRow row = sheet.createRow(0);
      // Data
      HSSFCell cell = row.createCell(0);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Data");
      // Agendas Matutino
      cell = row.createCell(1);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Agendas Matutino");
      // Agendas Vespertino
      cell = row.createCell(2);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Agendas Vespertino");

      try
      {
         gravar(workbook);
      }
      catch (IOException e)
      {
         logger.error(e.getMessage(), e);
      }
   }

   protected void criarNovaPlanilhaConclusoes(HSSFWorkbook workbook, HSSFCellStyle... cellStyles)
   {
      HSSFSheet sheet = workbook.createSheet(SHEET_CONCLUSOES);

      // Linha do Cabeçalho
      HSSFRow row = sheet.createRow(0);
      // Tipo
      HSSFCell cell = row.createCell(0);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Conclusão");

      try
      {
         gravar(workbook);
      }
      catch (IOException e)
      {
         logger.error(e.getMessage(), e);
      }
   }

   protected void criarNovaPlanilhaEmpresas(HSSFWorkbook workbook, HSSFCellStyle... cellStyles)
   {
      HSSFSheet sheet = workbook.createSheet(SHEET_EMPRESAS);

      // Linha do Cabeçalho
      HSSFRow row = sheet.createRow(0);
      // Empresa
      HSSFCell cell = row.createCell(0);
      cell.setCellValue("Empresa");
      cell.setCellStyle(cellStyles[0]);
      // Tipo
      cell = row.createCell(1);
      cell.setCellValue("Tipo");
      cell.setCellStyle(cellStyles[0]);

      try
      {
         gravar(workbook);
      }
      catch (IOException e)
      {
         logger.error(e.getMessage(), e);
      }
   }

   protected void criarNovaPlanilhaMedicos(HSSFWorkbook workbook, HSSFCellStyle... cellStyles)
   {
      HSSFSheet sheet = workbook.createSheet(SHEET_MEDICOS);
      // Linha do Cabeçalho
      HSSFRow row = sheet.createRow(0);
      // Ativo
      HSSFCell cell = row.createCell(0);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Ativo");
      // Nome
      cell = row.createCell(1);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Nome");

      try
      {
         gravar(workbook);
      }
      catch (IOException e)
      {
         logger.error(e.getMessage(), e);
      }
   }

   protected void criarNovaPlanilhaTipoExames(HSSFWorkbook workbook, HSSFCellStyle... cellStyles)
   {
      HSSFSheet sheet = workbook.createSheet(SHEET_TIPOEXAMES);

      // Linha do Cabeçalho
      HSSFRow row = sheet.createRow(0);
      // Tipo
      HSSFCell cell = row.createCell(0);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Tipo");

      try
      {
         gravar(workbook);
      }
      catch (IOException e)
      {
         logger.error(e.getMessage(), e);
      }
   }

   protected void criarNovaPlanilhaTurnos(HSSFWorkbook workbook, HSSFCellStyle... cellStyles)
   {
      HSSFSheet sheet = workbook.createSheet(SHEET_TURNOS);

      // Linha do Cabeçalho
      HSSFRow row = sheet.createRow(0);
      // Turno
      HSSFCell cell = row.createCell(0);
      cell.setCellStyle(cellStyles[0]);
      cell.setCellValue("Turno");

      try
      {
         gravar(workbook);
      }
      catch (IOException e)
      {
         logger.error(e.getMessage(), e);
      }
   }

   protected HSSFCellStyle getCellStyleCabecalho(HSSFWorkbook workbook)
   {
      if (cellStyleCabecalho == null)
      {
         getFontCabecalho(workbook);

         cellStyleCabecalho = workbook.createCellStyle();
         cellStyleCabecalho.setFont(workbook.getFontAt((short) 5));
         cellStyleCabecalho.setAlignment(HSSFCellStyle.ALIGN_CENTER);
         cellStyleCabecalho.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
         cellStyleCabecalho.setFillForegroundColor(new HSSFColor.DARK_GREEN().getIndex());
         cellStyleCabecalho.setBorderBottom(HSSFCellStyle.BORDER_THIN);
         cellStyleCabecalho.setBottomBorderColor(HSSFColor.BLACK.index);
         cellStyleCabecalho.setBorderLeft(HSSFCellStyle.BORDER_THIN);
         cellStyleCabecalho.setLeftBorderColor(HSSFColor.BLACK.index);
         cellStyleCabecalho.setBorderRight(HSSFCellStyle.BORDER_THIN);
         cellStyleCabecalho.setRightBorderColor(HSSFColor.BLACK.index);
         cellStyleCabecalho.setBorderTop(HSSFCellStyle.BORDER_THIN);
         cellStyleCabecalho.setTopBorderColor(HSSFColor.BLACK.index);
      }

      return cellStyleCabecalho;
   }

   private HSSFFont getFontCabecalho(HSSFWorkbook workbook)
   {
      if ((workbook.getNumberOfFonts() < 5 || workbook.getFontAt((short) 5) == null) && fontCabecalho == null)
      {
         // Fonte para cabeçalho (idx == 5)
         fontCabecalho = workbook.createFont();
         fontCabecalho.setItalic(false);
         fontCabecalho.setFontHeightInPoints((short) 10);
         fontCabecalho.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
         fontCabecalho.setColor(new HSSFColor.WHITE().getIndex());
      }

      return fontCabecalho;
   }

   private HSSFFont getFontGeral(HSSFWorkbook workbook)
   {
      if ((workbook.getNumberOfFonts() < 6 || workbook.getFontAt((short) 6) == null) && fontGeral == null)
      {
         // Fonte geral para preenchimento da tabela (idx == 6)
         fontGeral = workbook.createFont();
         fontGeral.setItalic(false);
         fontGeral.setFontHeightInPoints((short) 10);
         fontGeral.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
         fontGeral.setColor(new HSSFColor.BLACK().getIndex());
      }

      return fontGeral;
   }

   /**
    * Nome para uma planilha conforme a data indicada.
    * 
    * @param date data que indica o nome da planilha.
    * @return nome da planilha.
    */
   private String obterNomeDaPlanilha(Date date)
   {
      return sheetNameDateFormat.format(date);
   }
}
